package org.amos.core.frame.aspect;

import ch.qos.logback.classic.Level;
import cn.hutool.core.exceptions.ExceptionUtil;
import lombok.extern.slf4j.Slf4j;
import org.amos.core.basic.annotation.Log;
import org.amos.core.basic.utils.JsonUtils;
import org.amos.core.frame.tool.log.AbstractOperateLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * @desc: 接口日志切面
 * @author: liubt
 * @date: 2022-08-11 10:25
 **/
@Slf4j
@Aspect
@Component
public class LogAspect extends AbstractOperateLog {

    private static final ThreadLocal<Long> startTime = new ThreadLocal<>();
    @Pointcut("@annotation(org.amos.core.basic.annotation.Log) ")
    public void cut() {
    }

    @Before("cut()")
    public void doBefore() {
        startTime.set(System.currentTimeMillis());
    }
    @AfterReturning(value = "cut()", returning = "rt")
    public void doAfterReturning(JoinPoint jp, Object rt) throws Throwable {
        try {
            MethodSignature methodSignature = (MethodSignature) jp.getSignature();
            Method method = methodSignature.getMethod();
            Log log = method.getAnnotation(Log.class);
            Object[] args = jp.getArgs();
            Class<?> clazz = jp.getTarget().getClass();
            long time = System.currentTimeMillis() - startTime.get();
            String resultInfo = log.logResultInfo() ? JsonUtils.objectToJson(rt) : JsonUtils.objectToJson(new HashMap<>());
            super.doService(log, clazz, method, args, resultInfo, Level.INFO.levelStr, time);
        } catch (Exception e) {
            log.error("OperateLogAspect doAfterReturning method has error,{}", e.getMessage());
        }
    }

    @AfterThrowing(pointcut = "cut()", throwing = "exception")
    public void doAfterThrowing(JoinPoint jp, Exception exception) throws Throwable {
        try {
            MethodSignature methodSignature = (MethodSignature) jp.getSignature();
            Method method = methodSignature.getMethod();
            Log log = method.getAnnotation(Log.class);
            Object[] args = jp.getArgs();
            Class<?> clazz = jp.getTarget().getClass();
            long time = System.currentTimeMillis() - startTime.get();
            super.doService(log, clazz, method, args, ExceptionUtil.stacktraceToString(exception), Level.ERROR.levelStr, time);
        } catch (Exception e) {
            log.error("OperateLogAspect doAfterThrowing method has error,{}", e.getMessage());
        }
    }

    @Override
    public void afterPropertiesSet() {
        if (excludeUrls == null) {
            excludeUrls = new ArrayList<>();
        }
        excludeUrls.add("/error");
        excludeUrls.add("/swagger-resources");
    }
}
